From c0aa065ac119c3280f0e886caff88258b767bb39 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 15 Nov 2016 06:19:16 +0100 Subject: [PATCH] snapshot: Convert GtkImage and GtkIconHelper Adds a bunch of new APIs to render textures with theming. FIXME: Cannot draw shadows for textures. --- gtk/gtkiconhelper.c | 17 +++---- gtk/gtkiconhelperprivate.h | 4 +- gtk/gtkimage.c | 99 +++++++++++++++++++------------------- gtk/gtkrendericon.c | 49 +++++++++++++++++++ gtk/gtkrendericonprivate.h | 5 ++ gtk/gtksnapshot.c | 52 ++++++++++++++++++++ gtk/gtksnapshot.h | 11 +++++ 7 files changed, 175 insertions(+), 62 deletions(-) diff --git a/gtk/gtkiconhelper.c b/gtk/gtkiconhelper.c index 278ace34ff..5bd099d547 100644 --- a/gtk/gtkiconhelper.c +++ b/gtk/gtkiconhelper.c @@ -857,27 +857,24 @@ _gtk_icon_helper_draw (GtkIconHelper *self, } } -GskRenderNode * -gtk_icon_helper_get_render_node (GtkIconHelper *self, - GskRenderer *renderer) +void +gtk_icon_helper_snapshot (GtkIconHelper *self, + GtkSnapshot *snapshot) { GskTexture *texture; GskRenderNode *node; graphene_rect_t bounds; - gtk_icon_helper_ensure_texture (self, renderer); + gtk_icon_helper_ensure_texture (self, gtk_snapshot_get_renderer (snapshot)); texture = self->priv->texture; if (texture == NULL) - return NULL; + return; graphene_rect_init (&bounds, 0, 0, gsk_texture_get_width (texture), gsk_texture_get_height (texture)); - node = gsk_renderer_create_render_node (renderer); - gsk_render_node_set_name (node, "Icon Helper"); - gsk_render_node_set_bounds (node, &bounds); + node = gtk_snapshot_append (snapshot, &bounds, "Icon Helper"); gsk_render_node_set_texture (node, texture); - - return node; + gsk_render_node_unref (node); } gboolean diff --git a/gtk/gtkiconhelperprivate.h b/gtk/gtkiconhelperprivate.h index 6576e81519..0fd324097b 100644 --- a/gtk/gtkiconhelperprivate.h +++ b/gtk/gtkiconhelperprivate.h @@ -125,8 +125,8 @@ void _gtk_icon_helper_draw (GtkIconHelper *self, cairo_t *cr, gdouble x, gdouble y); -GskRenderNode * gtk_icon_helper_get_render_node (GtkIconHelper *self, - GskRenderer *renderer); +void gtk_icon_helper_snapshot (GtkIconHelper *self, + GtkSnapshot *snapshot); gboolean _gtk_icon_helper_get_force_scale_pixbuf (GtkIconHelper *self); void _gtk_icon_helper_set_force_scale_pixbuf (GtkIconHelper *self, diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c index f7abcfcb94..ffb5f81d6d 100644 --- a/gtk/gtkimage.c +++ b/gtk/gtkimage.c @@ -142,8 +142,8 @@ struct _GtkImagePrivate #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_BUTTON -static GskRenderNode *gtk_image_get_render_node (GtkWidget *widget, - GskRenderer *renderer); +static void gtk_image_snapshot (GtkWidget *widget, + GtkSnapshot *snapshot); static void gtk_image_size_allocate (GtkWidget *widget, GtkAllocation*allocation); static void gtk_image_unmap (GtkWidget *widget); @@ -163,6 +163,13 @@ static void gtk_image_get_content_size (GtkCssGadget *gadget, gint *minimum_baseline, gint *natural_baseline, gpointer unused); +static gboolean gtk_image_render_contents (GtkCssGadget *gadget, + GtkSnapshot *snapshot, + int x, + int y, + int width, + int height, + gpointer data); static void gtk_image_style_updated (GtkWidget *widget); static void gtk_image_finalize (GObject *object); @@ -211,7 +218,7 @@ gtk_image_class_init (GtkImageClass *class) gobject_class->finalize = gtk_image_finalize; widget_class = GTK_WIDGET_CLASS (class); - widget_class->get_render_node = gtk_image_get_render_node; + widget_class->snapshot = gtk_image_snapshot; widget_class->measure = gtk_image_measure; widget_class->size_allocate = gtk_image_size_allocate; widget_class->unmap = gtk_image_unmap; @@ -367,8 +374,9 @@ gtk_image_init (GtkImage *image) gtk_image_get_content_size, NULL, NULL, - NULL, + gtk_image_render_contents, NULL, NULL); + } static void @@ -1403,69 +1411,60 @@ gtk_image_get_content_size (GtkCssGadget *gadget, } -static GskRenderNode * -gtk_image_get_render_node (GtkWidget *widget, - GskRenderer *renderer) +static void +gtk_image_snapshot (GtkWidget *widget, + GtkSnapshot *snapshot) { - GtkImage *image = GTK_IMAGE (widget); - GtkImagePrivate *priv = image->priv; - gint w, h, baseline; - gint x, y, width, height; - GskRenderNode *res; - GskRenderNode *node; - GtkAllocation alloc, clip; - cairo_t *cr; - - res = gtk_css_gadget_get_render_node (priv->gadget, renderer, FALSE); - - if (res == NULL) - return NULL; - - if (gtk_image_get_storage_type (image) == GTK_IMAGE_ANIMATION) - { - node = gtk_widget_create_render_node (widget, renderer, "Image Content"); + gtk_css_gadget_snapshot (GTK_IMAGE (widget)->priv->gadget, + snapshot); +} - gtk_widget_get_clip (widget, &clip); - _gtk_widget_get_allocation (widget, &alloc); +static gboolean +gtk_image_render_contents (GtkCssGadget *gadget, + GtkSnapshot *snapshot, + int x, + int y, + int width, + int height, + gpointer data) +{ + GtkWidget *widget; + GtkImage *image; + GtkImagePrivate *priv; + gint w, h, baseline; - cr = gsk_render_node_get_draw_context (node, renderer); - cairo_translate (cr, alloc.x - clip.x, alloc.y - clip.y); - x = 0; - y = 0; - width = alloc.width; - height = alloc.height; + widget = gtk_css_gadget_get_owner (gadget); + image = GTK_IMAGE (widget); + priv = image->priv; - _gtk_icon_helper_get_size (priv->icon_helper, &w, &h); + _gtk_icon_helper_get_size (priv->icon_helper, &w, &h); - baseline = gtk_widget_get_allocated_baseline (widget); + baseline = gtk_widget_get_allocated_baseline (widget); - if (baseline == -1) - y += floor(height - h) / 2; - else - y += CLAMP (baseline - h * gtk_image_get_baseline_align (image), 0, height - h); + if (baseline == -1) + y += floor(height - h) / 2; + else + y += CLAMP (baseline - h * gtk_image_get_baseline_align (image), 0, height - h); - x += (width - w) / 2; + x += (width - w) / 2; + gtk_snapshot_translate_2d (snapshot, x, y); + if (gtk_image_get_storage_type (image) == GTK_IMAGE_ANIMATION) + { GtkStyleContext *context = gtk_widget_get_style_context (widget); GdkPixbuf *pixbuf = get_animation_frame (image); - gtk_render_icon (context, cr, pixbuf, x, y); + gtk_snapshot_render_icon (snapshot, context, pixbuf, x, y); + g_object_unref (pixbuf); - - cairo_destroy (cr); } else { - node = gtk_icon_helper_get_render_node (priv->icon_helper, renderer); - } - - if (node != NULL) - { - gsk_render_node_append_child (res, node); - gsk_render_node_unref (node); + gtk_icon_helper_snapshot (priv->icon_helper, snapshot); } + gtk_snapshot_translate_2d (snapshot, -x, -y); - return res; + return FALSE; } static void diff --git a/gtk/gtkrendericon.c b/gtk/gtkrendericon.c index b2ca78aeb6..cd43ec9ecb 100644 --- a/gtk/gtkrendericon.c +++ b/gtk/gtkrendericon.c @@ -26,6 +26,7 @@ #include "gtkcssshadowsvalueprivate.h" #include "gtkcssstyleprivate.h" #include "gtkcsstransformvalueprivate.h" +#include "gtksnapshotprivate.h" #include @@ -222,3 +223,51 @@ gtk_css_style_render_icon_get_extents (GtkCssStyle *style, extents->height += border.top + border.bottom; } +void +gtk_css_style_snapshot_icon (GtkCssStyle *style, + GtkSnapshot *snapshot, + GskTexture *texture) +{ + const GtkCssValue *shadows, *transform; + cairo_matrix_t transform_matrix; + graphene_matrix_t matrix, other, saved_matrix; + graphene_rect_t bounds; + GskRenderNode *node; + int width, height; + + g_return_if_fail (GTK_IS_CSS_STYLE (style)); + g_return_if_fail (snapshot != NULL); + g_return_if_fail (GSK_IS_TEXTURE (texture)); + + shadows = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_SHADOW); + transform = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_TRANSFORM); + width = gsk_texture_get_width (texture); + height = gsk_texture_get_height (texture); + + if (!_gtk_css_transform_value_get_matrix (transform, &transform_matrix)) + return; + + graphene_matrix_init_from_matrix (&saved_matrix, gtk_snapshot_get_transform (snapshot)); + + /* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */ + graphene_matrix_init_translate (&matrix, &(graphene_point3d_t)GRAPHENE_POINT3D_INIT(width / 2.0, height / 2.0, 0)); + graphene_matrix_init_from_2d (&other, transform_matrix.xx, transform_matrix.yx, + transform_matrix.xy, transform_matrix.yy, + transform_matrix.x0, transform_matrix.y0); + graphene_matrix_multiply (&other, &matrix, &matrix); + graphene_matrix_init_translate (&other, &(graphene_point3d_t)GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0)); + graphene_matrix_multiply (&matrix, &other, &matrix); + gtk_snapshot_transform (snapshot, &matrix); + + graphene_rect_init (&bounds, 0, 0, width, height); + + node = gtk_snapshot_append (snapshot, &bounds, "Icon"); + if (!_gtk_css_shadows_value_is_none (shadows)) + { + g_warning ("Painting shadows not implemented for textures yet."); + } + gsk_render_node_set_texture (node, texture); + gsk_render_node_unref (node); + + gtk_snapshot_set_transform (snapshot, &saved_matrix); +} diff --git a/gtk/gtkrendericonprivate.h b/gtk/gtkrendericonprivate.h index f627655f2a..83a3b04cc6 100644 --- a/gtk/gtkrendericonprivate.h +++ b/gtk/gtkrendericonprivate.h @@ -22,8 +22,10 @@ #include #include +#include #include "gtkcsstypesprivate.h" +#include "gtksnapshot.h" #include "gtktypes.h" G_BEGIN_DECLS @@ -41,6 +43,9 @@ void gtk_css_style_render_icon_surface (GtkCssStyle *style, cairo_surface_t *surface, double x, double y); +void gtk_css_style_snapshot_icon (GtkCssStyle *style, + GtkSnapshot *snapshot, + GskTexture *texture); void gtk_css_style_render_icon_get_extents (GtkCssStyle *style, GdkRectangle *extents, diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c index 62defef2b7..aacb24f76d 100644 --- a/gtk/gtksnapshot.c +++ b/gtk/gtksnapshot.c @@ -24,6 +24,7 @@ #include "gtkcssshadowsvalueprivate.h" #include "gtkrenderbackgroundprivate.h" #include "gtkrenderborderprivate.h" +#include "gtkrendericonprivate.h" #include "gtkstylecontextprivate.h" #include "gsk/gskrendernodeprivate.h" @@ -185,6 +186,39 @@ gtk_snapshot_append_node (GtkSnapshot *state, } } +GskRenderNode * +gtk_snapshot_append (GtkSnapshot *state, + const graphene_rect_t *bounds, + const char *name, + ...) +{ + GskRenderNode *node; + + g_return_val_if_fail (state != NULL, NULL); + g_return_val_if_fail (bounds != NULL, NULL); + + node = gsk_renderer_create_render_node (state->renderer); + gsk_render_node_set_bounds (node, bounds); + + if (name) + { + va_list args; + char *str; + + va_start (args, name); + str = g_strdup_vprintf (name, args); + va_end (args); + + gsk_render_node_set_name (node, str); + + g_free (str); + } + + gtk_snapshot_append_node (state, node); + + return node; +} + cairo_t * gtk_snapshot_append_cairo_node (GtkSnapshot *state, const graphene_rect_t *bounds, @@ -357,3 +391,21 @@ gtk_snapshot_render_layout (GtkSnapshot *state, gtk_snapshot_translate_2d (state, -x, -y); } +void +gtk_snapshot_render_icon (GtkSnapshot *snapshot, + GtkStyleContext *context, + GdkPixbuf *pixbuf, + gdouble x, + gdouble y) +{ + GskTexture *texture; + + texture = gsk_texture_new_for_pixbuf (snapshot->renderer, pixbuf); + gtk_snapshot_translate_2d (snapshot, x, y); + gtk_css_style_snapshot_icon (gtk_style_context_lookup_style (context), + snapshot, + texture); + gtk_snapshot_translate_2d (snapshot, -x, -y); + gsk_texture_unref (texture); +} + diff --git a/gtk/gtksnapshot.h b/gtk/gtksnapshot.h index 74be2c134b..20315b0f97 100644 --- a/gtk/gtksnapshot.h +++ b/gtk/gtksnapshot.h @@ -73,6 +73,11 @@ GDK_AVAILABLE_IN_3_90 void gtk_snapshot_append_node (GtkSnapshot *state, GskRenderNode *node); GDK_AVAILABLE_IN_3_90 +GskRenderNode * gtk_snapshot_append (GtkSnapshot *state, + const graphene_rect_t *bounds, + const char *name, + ...) G_GNUC_PRINTF(3, 4); +GDK_AVAILABLE_IN_3_90 cairo_t * gtk_snapshot_append_cairo_node (GtkSnapshot *state, const graphene_rect_t *bounds, const char *name, @@ -117,6 +122,12 @@ void gtk_snapshot_render_insertion_cursor (GtkSnapshot PangoLayout *layout, int index, PangoDirection direction); +GDK_AVAILABLE_IN_3_90 +void gtk_snapshot_render_icon (GtkSnapshot *snapshot, + GtkStyleContext *context, + GdkPixbuf *pixbuf, + gdouble x, + gdouble y); G_END_DECLS -- 2.30.2